// JavaScript Document
//Gesture.js
//为手势提供便利操作，同时考虑移动端和PC端
//目前支持长按
function Gesture(element)
{
	var Gesture=new Object;
	Gesture.Element=element;//获取元素
	Gesture.Element.LeftBorder=0;//左边界
	Gesture.Element.RightBorder=0;//右边界
	Gesture.Element.TopBorder=0;//顶边界,仅作保留未被启用
	Gesture.Element.BottomBorder=0;//底边界，仅作保留未被启用
	Gesture.Element.EdgeWidth=0;
	//要注意的是，当元素被移动后需要重新计算边界（缩放不需要，这里缩放指的是网页的缩放）
	CalculateParameters();//计算参数
	Gesture.TouchTimeBegin=null;//记录鼠标按下或者手机点击屏幕的事件
	Gesture.TouchTimeEnd=0;//记录鼠标抬起或者手指离开的时间
	Gesture.TimeContinue=0;//记录鼠标持续按压事件或者手指持续点击时间
	//Gesture.Element.OnClick=element.onclick;//记录点击事件
	//element.onclick=null;
	//Gesture.OnTap=element.ontap;//记录手指点击事件,后被抛弃
	//Gesture.TouchMoveDefault=element.ontouchmove;//记录原本手指移动事件,后被抛弃
	//Gesture.TouchStartDefault=element.ontouchstart;//,后被抛弃
	Gesture.OnPress=null;//按压的触发事件。可以外界直接赋值。但是直接赋值的话可能不能很好的适应多个绑定函数
	Gesture.OnPressEnd=null;
	Gesture.Presses=Array();//按压的出发事件，通过绑定函数可以绑定多个函数。
	Gesture.PressEnds=Array();
	Gesture.OnTap=null;//点击事件，优先于click事件响应。
	Gesture.OnTapEnd=null;
	Gesture.Taps=Array();
	Gesture.TapEnds=Array();
	Gesture.OnDbTap=null;//双击
	Gesture.OnDbTapEnd=null;
	Gesture.DbTaps=Array();
	Gesture.DbTapEnds=Array();
	Gesture.OnSlide=null;//滑动手势
	Gesture.OnSlideEnd=null;
	Gesture.Slides=Array();//滑动手势，通过绑定函数可以绑定多个函数
	Gesture.SlideEnds=Array();
	Gesture.IfVertical=false;//是否开启上下滑动
	Gesture.EdgeLeftSlide=null;//边缘左滑手势
	Gesture.EdgeLeftSlideEnd=null;
	Gesture.EdgeLeftSlides=Array();//边缘左滑手势，通过绑定函数可以绑定多个函数。
	Gesture.EdgeLeftSlideEnds=Array();
	Gesture.EdgeRightSlide=null;//边缘右滑手势
	Gesture.EdgeRightSlideEnd=null;//边缘右滑结束时候操作函数
	Gesture.EdgeRightSlides=Array();//边缘右滑手,势通过绑定函数可以绑定多个函数。
	Gesture.EdgeRightSlideEnds=Array();
	Gesture.LeftSlide=null;//左滑手势
	Gesture.LeftSlideEnd=null;
	Gesture.LeftSlides=Array();//左滑手势，通过绑定函数可以绑定多个函数。
	Gesture.LeftSlideEnds=Array();
	Gesture.RightSlide=null;//右滑手势
	Gesture.RightSlideEnd=null;
	Gesture.RightSlides=Array();//右滑手势，通过绑定函数可以绑定多个函数。
	Gesture.RightSlideEnds=Array();
	Gesture.IfEdge=false;//滑动时是否从边缘滑动
	Gesture.IntervalID=null;//这个主要用于Press判断
	Gesture.TimeoutID=null;//这个主要用于双击判断
	Gesture.TimeoutTime=200;//设置间隔（主要是双击之间的允许间隔）
	Gesture.IntervalTime=20;
	Gesture.FingerNumber=0;//手指数目
	Gesture.MoveX=0;//在水平方向上移动的距离
	Gesture.MoveY=0;//在竖直方向上移动的位置
	Gesture.TouchX=0;//当前触摸点在X轴上位置
	Gesture.TouchY=0;//当前触摸点在Y轴上位置
	Gesture.MoveXSpeed=0;//在水平方向上移动的速度
	Gesture.MoveYSpeed=0;//在竖直方向上移动的速度
	Gesture.XBegin=null;
	Gesture.YBegin=null;
	Gesture.GestureNow=null;
	Gesture.Direction=null;//手指移动方向
	Gesture.DbJudge=0;//双击判断,默认是0
	Gesture.Tag=false;//用于标记一次活动，
	Gesture.BindEvent=function(E,Func){BindEvent(E,Func);};
	Gesture.UnBindEvent=function(E,Func){UnBindEvent(E,Func);};
	/*Gesture.PreventDefault=function (){
											event.preventDefault();
											//Gesture.Element.onclick=null;
											//Gesture.Element.ontouchmove=null;
									   };//将原有点击事件制空*/
	Gesture.Element.addEventListener('mousedown',function (e){PressBegin(e);},false);
	Gesture.Element.addEventListener('touchstart',function (e){PressBegin(e);},false);
	Gesture.Element.addEventListener('mouseup',function (e){PressEnd(e);},false);
	Gesture.Element.addEventListener('touchend',function (e){PressEnd(e);},false);
	var BrowserVersion=navigator.appVersion;//浏览器类型
	var Events=Array('Press','Tap','DbTap','Slide','EdgeLeftSlide','LeftSlide','EdgeRightSlide','RightSlide','PressEnd','TapEnd','DbTapEnd','SlideEnd','EdgeLeftSlideEnd','LeftSlideEnd','EdgeRightSlideEnd','RightSlideEnd');//事件类型的集合
	var OnFunctions=Array(Gesture.OnPress,Gesture.OnTap,Gesture.OnDbTap,Gesture.OnSlide,Gesture.EdgeLeftSlide,Gesture.LeftSlide,Gesture.EdgeRightSlide,Gesture.RightSlide);//事件函数，仅作为声明模板用，下面在函数里面还是需要重新用
	var Functions=Array(Gesture.Presses,Gesture.Taps,Gesture.DbTaps,Gesture.Slides,Gesture.EdgeLeftSlides,Gesture.LeftSlides,Gesture.EdgeRightSlides,Gesture.RightSlides);//事件对应得函数集
	var OnEndFunctions=Array(Gesture.OnPressEnd,Gesture.OnTapEnd,Gesture.OnDbTapEnd,Gesture.OnSlideEnd,Gesture.EdgeLeftSlideEnd,Gesture.LeftSlideEnd,Gesture.EdgeRightSlideEnd,Gesture.RightSlideEnd);//结束函数
	var EndFunctions=Array(Gesture.PressEnds,Gesture.TapEnds,Gesture.DbTapEnds,Gesture.SlideEnds,Gesture.EdgeLeftSlideEnds,Gesture.LeftSlideEnds,Gesture.EdgeRightSlideEnds,Gesture.RightSlideEnds);//事件结束函数集
	return Gesture;
	function BindEvent(E,Func)//绑定事件
	{
		if ((Func==null)||(E==null))
			return false;
		var Event=IsInArray(E,Events,true);
		if (Event==-1)//参数错误
			return false;
		else
		{
			if (Event<=7)//绑定的是动作执行函数
			{
				if (IsInArray(Func,Functions[Event],false)==-1)//函数还不存在
					Functions[Event].push(Func);
				else
					return false;
			}
			else //绑定的是动作结束的运行函数
			{
				Event=Event-8;
				if (IsInArray(Func,EndFunctions[Event],false)==-1)//函数还不存在
					EndFunctions[Event].push(Func);
				else
					return false;	
			}
		}
	}
	function UnBindEvent(E,Func)//解绑函数
	{
		if ((Func==null)||(E==null))
			return false;
		var Event=IsInArray(E,Events,true);
		if (Event==-1)//参数错误
			return false;
		else
		{
			if (Event<=7)
			{
				var IfInArray=IsInArray(Func,Functions[Event],false);//在函数的位置
				if (IfInArray==-1)//函数还不存在
					return false;
				else
				{
					Functions[Event].splice(IfInArray,1);//删除
				}
			}
			else 
			{
				Event=Event-8;
				var IfInArray=IsInArray(Func,EndFunctions[Event],false);//在函数的位置
				if (IfInArray==-1)//函数还不存在
					return false;
				else
				{
					EndFunctions[Event].splice(IfInArray,1);//删除
				}	
			}
		}	
	}
	function IsInArray(content,array,IfCase)//是否忽视大小写，默认不忽视,传递true表示忽视
	//返回位置，不存在则返回-1
	{
		if ((content==null)||(content==""))
			return -1;
		if (IfCase)
			var Content=content.toString().toUpperCase();//转化为全大写
		for (var i=0;i<array.length;++i)
		{
			if (IfCase)
			{
				var Compare=array[i].toString().toUpperCase();//转化为全大写
				if (Content==Compare)
				{
					return i;
				}
			}
			else
			{
				if (content==array[i])
					return i;	
			}
			
		}
		return -1;
	}
	function CalculateParameters()//计算手势区域的各个参数
	{
		Gesture.Element.LeftBorder=Number(Gesture.Element.offsetLeft);//左边界
		Gesture.Element.RightBorder=Number(Gesture.Element.offsetWidth)+Number(Gesture.Element.offsetLeft);//右边界
		Gesture.Element.TopBorder=Number(Gesture.Element.offsetTop);//顶边界,仅作保留未被启用
		Gesture.Element.BottomBorder=Number(Gesture.Element.offsetHeight)+Number(Gesture.Element.offsetTop);//底边界，仅作保留未被启用
		if (Number(Gesture.Element.offsetWidth)*0.15>10)
		{
			if (Number(Gesture.Element.offsetWidth)*0.15>50)
				Gesture.Element.EdgeWidth=50;
			else
				Gesture.Element.EdgeWidth=Number(Gesture.Element.offsetWidth)*0.15;
		}
		else
		{
			Gesture.Element.EdgeWidth=10;	
		}		
	}
	function RemoveDefault()
	{
		event.preventDefault();	
	}
	function EndOneListen()//结束一次监听
	{
		ExecuteGestureEndFunction();//执行手势结束函数
		Gesture.XBegin=null;//将触控点开始位置置为null
		Gesture.YBegin=null;
		Gesture.TouchTimeBegin=null;//触控开始时间置为null
		Gesture.TimeContinue=0;
		clearInterval(Gesture.IntervalID);//清空循环
		clearTimeout(Gesture.TimeoutID);//清空循环
		Gesture.IntervalID=null;
		Gesture.TimeoutID=null;
		Gesture.GestureNow=null;
		Gesture.Element.removeEventListener('mousemove',Move,false);//移除Move监听	
		Gesture.Element.removeEventListener('mousemove',RemoveDefault,false);//恢复正常滚动
		Gesture.Element.removeEventListener('touchmove',RemoveDefault,false);//恢复正常滚动
		Gesture.Element.removeEventListener('touchmove',Move,false);//移除Move监听
		Gesture.Tag=false;
		CalculateParameters();
	}
	function ExecuteGestureEndFunction()//执行手势结束函数
	{
		var OnEndFunctions=Array(Gesture.OnPressEnd,Gesture.OnTapEnd,Gesture.OnDbTapEnd,Gesture.OnSlideEnd,Gesture.EdgeLeftSlideEnd,Gesture.LeftSlideEnd,Gesture.EdgeRightSlideEnd,Gesture.RightSlideEnd);//结束函数,这里还是要重新声明一下，因为字符串是不变的
		var Event=IsInArray(Gesture.GestureNow,Events,true);
		if ((Event==-1)||(Event>7))
		{
			return;
		}
		else
		{
			if (OnEndFunctions[Event]!=null)//执行结束函数
				OnEndFunctions[Event]();
			for (var i=0;i<EndFunctions[Event].length;++i)	
				EndFunctions[Event][i]();
		}
	}
	function PressBegin(event)//鼠标点下或者手指按下
	{
		if (event.type=="touchstart")
		{
			if (event.touches.length>1)
			{
				EndOneListen();//表示该次倾听终止
				return;	
			}
			else
				e=event.touches[0];
		}
		else
		{
			e=event;
		}
		if ((Gesture.OnPress!=null)||(Gesture.Presses.length!=0))//说明存在长按操作，那么禁止user-select功能
		{
			if (Gesture.Element.style.cssText.indexOf("-webkit-user-select:none")==-1)//判断是否已经有了禁止长按的语句，若没有则添加
				Gesture.Element.style.cssText+="-webkit-user-select:none";
		}
		Gesture.TouchTimeBegin=GetTime();
		Gesture.XBegin=e.pageX;
		Gesture.YBegin=e.pageY;
		Gesture.TimeContinue=0;//初始化
		if ((Gesture.OnDbTap!=null)||(Gesture.DbTaps.length!=0))//存在双击操作
		{
			if (Gesture.DbJudge==0)//说明是第一次点击，那么加一进入监听状态。同时
			{
				Gesture.DbJudge=1;
			}
			else if (Gesture.DbJudge==1)//说明可以触动双击事件了，并消除setTimeout的时间
			{
				if (Gesture.TimeoutID!=null)//说明Timeout在走
				{
					Gesture.DbJudge=2;	
					clearTimeout(Gesture.TimeoutID);
					Gesture.TimeoutID=null;
				}
				else
					Gesture.DbJudge=0;
			}
			else
				Gesture.DbJudge=0;
		}
		if (Gesture.IntervalID==null)//这样做是为了避免多次执行setInterval函数
		{
			Gesture.IntervalID=setInterval(function(){PressJudge();},50);
		}
		Gesture.Element.addEventListener('touchmove',Move,false);//添加监听事件
		Gesture.Element.addEventListener('touchmove',RemoveDefault,false);//添加监听事件,即先阻止默认的滑动事件
		Gesture.Element.addEventListener('mousemove',Move,false);//添加监听事件
		Gesture.Element.addEventListener('mousemove',RemoveDefault,false);//添加监听事件,即先阻止默认的滑动事件
	}
	function PressJudge()//判断是否执行了长按操作
	{
		Gesture.TimeContinue+=50;//表明过去了50ms，但是实际上会比实际的要多50ms
		if (Gesture.TimeContinue>500)
		{
			if (Gesture.OnPress!=null)
			{	
				Gesture.OnPress();
			}
			for (var i=0;i<Gesture.Presses.length;++i)
				Gesture.Presses[i]();
			Gesture.GestureNow="Press";//将当前手势定义为按压
			EndOneListen();//表示该次倾听终止
			return;
		}	
	}
	function Move(event)//获取鼠标位置或者触点位置
	{	
		if (event.type=="touchmove")
			e=event.touches[0];
		else
			e=event;
		Gesture.TouchX=e.pageX;
		Gesture.TouchY=e.pageY;
		if ((Gesture.XBegin==null)||(Gesture.YBegin==null))
		{
			return;
		}
		var MoveX=Number(e.pageX)-Number(Gesture.XBegin)
		var MoveY=Number(e.pageY)-Number(Gesture.YBegin);
		Gesture.MoveX=MoveX;//赋值X坐标轴移动距离
		Gesture.MoveY=MoveY;//赋值Y坐标轴移动距离
		if (Gesture.GestureNow!=null)//说明已经触发了一个手势了
		{
			var OnFunctions=Array(Gesture.OnPress,Gesture.OnTap,Gesture.OnDbTap,Gesture.OnSlide,Gesture.EdgeLeftSlide,Gesture.LeftSlide,Gesture.EdgeRightSlide,Gesture.RightSlide);//事件函数，仅作为声明用，下面在函数里面还是需要重新用
			var EventNumber=IsInArray(Gesture.GestureNow,Events,true);
			if ((EventNumber!=-1)&&(EventNumber<=7))//显然这里的手势不应当是结束手势
			{
				if (OnFunctions[EventNumber]!=null)
					OnFunctions[EventNumber]();	
				for (var i=0;i<Functions[EventNumber].length;++i)
				{
					Functions[EventNumber][i]();	
				}
			}
			return;	
		}
		if ((Math.abs(MoveX)>5)||(Math.abs(MoveY)>5))//如果发生了移动，那么就开始了判断
		{
			clearInterval(Gesture.IntervalID);//清空循环
			Gesture.TimeContinue=0;//将按压时间置为0
			Gesture.TimeContinue=GetTime()-Gesture.TouchTimeBegin;//获取当前已经触摸用时
			if ((Gesture.LeftSlide==null)&&(Gesture.OnSlide==null)&&(Gesture.RightSlide==null)&&(Gesture.EdgeLeftSlide==null)&&(Gesture.EdgeRightSlide==null)&&(Gesture.LeftSlides.length==0)&&(Gesture.EdgeLeftSlides.length==0)&&(Gesture.RightSlides.length==0)&&(Gesture.EdgeRightSlides.length==0)&&(Gesture.Slides.length==0))//根本没有监听事件
			{
				EndOneListen();
				return;
			}
			var IfVertical=false;//是否上下滑动
			if (Math.abs(MoveX)<1*Math.abs(MoveY))//说明其实更可能是下滑动或者上滑动
			{
				if (Gesture.IfVertical)//如果有控制上下滑动的需求
					IfVertical=true;
				else
				{
					EndOneListen();
					return;
				}
			}
			if (IfVertical)//说明前期的滑动是上下的
			{
				if ((Gesture.OnSlide!=null)||(Gesture.Slides.length!=null))//存在滑动的手势
				{
					Gesture.GestureNow="Slide";
					return;
				}
				else//就算允许上下滑动监控并且确实上下滑动了，也是无效的
				{
					EndOneListen();
					return;	
				}
			}
			if (MoveX>0)//方向Right表示出触发左滑手势，方向Left表示触发右滑手势.同时判断是否是边缘手势
			{
				Gesture.Direction="Right";//说明手指的移动方向是向右，触发右滑手势（包含屏幕左边缘的右滑手势）
				if ((Number(Gesture.XBegin)-Number(Gesture.Element.LeftBorder))<Gesture.Element.EdgeWidth)//说明是从边缘触发的
					Gesture.IfEdge=true;
				else
					Gesture.IfEdge=false;	
			}
			else
			{
				Gesture.Direction="Left";
				if ((Number(Gesture.Element.RightBorder)-Number(Gesture.XBegin))<Gesture.Element.EdgeWidth)//说明是从边缘触发的
					Gesture.IfEdge=true;
				else
					Gesture.IfEdge=false;
			}
			if ((Gesture.Direction=="Left")&&((Gesture.LeftSlide!=null)||(Gesture.EdgeLeftSlide!=null)||(Gesture.LeftSlides.length!=0)||(Gesture.EdgeLeftSlides.length!=0)))//存在左滑手势操作
			{
				if (((Gesture.EdgeLeftSlide!=null)||(Gesture.EdgeLeftSlides.length!=0))&&(Gesture.IfEdge))
				{
					Gesture.GestureNow="EdgeLeftSlide";
					Gesture.Tag=true;
				}
				else if ((Gesture.LeftSlide!=null)||(Gesture.LeftSlides.length!=0))
				{
					Gesture.GestureNow="LeftSlide";
					Gesture.Tag=true;
				}
				else
				{
					EndOneListen();
				}
			}
			else if ((Gesture.Direction=="Right")&&((Gesture.RightSlide!=null)||(Gesture.EdgeRightSlide!=null)||(Gesture.RightSlides.length!=0)||(Gesture.EdgeRightSlides.length!=0)))//存在左滑手势操作
			{
				if ((Gesture.IfEdge)&&((Gesture.EdgeRightSlide!=null)||(Gesture.EdgeRightSlides.length!=0)))
				{
					Gesture.GestureNow="EdgeRightSlide";
				}
				else if ((Gesture.RightSlide!=null)||(Gesture.RightSlides.length!=0))
				{
					Gesture.GestureNow="RightSlide";
				}
				else
				{
					EndOneListen();
				}
			}
			else if ((Gesture.OnSlide!=null)||(Gesture.Slides.length!=null))
			{
				Gesture.GestureNow="Slide";;
			}	
			else
			{
				EndOneListen();	
			}
		}
	}
	function GetTime()
	{
		var date=new Date;
		return date.getTime();
	}
	
	function PressEnd(event)//鼠标停止按压或者手指离开
	{
		Gesture.TouchTimeEnd=GetTime();//获取结束时间
		if (event.type=="touchend")
		{
			e=event.touches[0];
		}
		else
			e=event;
		if (Gesture.TouchTimeBegin>=Gesture.TouchTimeEnd)
		{
			EndOneListen();//终止该次监听
			return;
		}
		else
		{
			var DelayTime=Number(Gesture.TouchTimeEnd)-Number(Gesture.TouchTimeBegin);
			if (Gesture.GestureNow!=null)//说明触发了手势操作，那么就不再执行Tap、DbTap、长按等操作
			{
				EndOneListen();//终止该次监听
				return;
			}
			else if (DelayTime>500)//说明该触发长按事件了
			{
				Gesture.GestureNow="Press";//将当前事件定义为长按
				EndOneListen();//终止该次监听
				event.stopPropagation();//阻止冒泡
				Gesture.TimeContinue=0;//
			}
			else
			{
				if ((Gesture.OnDbTap==null)&&(Gesture.DbTaps.length==0))//根本没有双击事件
				{
					StartTap();
				}
				else//存在双击事件，那么我们需要判断是继续执行单击事件还是执行双击事件
				{
					if (Gesture.DbJudge!=2)
					{
						if (Gesture.TimeoutID==null)
							Gesture.TimeoutID=setTimeout(StartTap,Gesture.TimeoutTime);;
					}
					else
					{
						StartDbTap();
					}
				}
			}	
		}
		return;
		function StartTap()//触发Tap事件或者click事件
		{
			if ((event.type=="touchend")&&((Gesture.DbTaps.length!=0)||(Gesture.OnDbTap!=null)))//如果存在双击事件并且事件是touchend，那么直接返回。
				return;																			//这是因为同时还会存在一个mouseup事件，不这样做会触发两次
			Gesture.GestureNow="Tap";//将当前事件定义为Tap																	
			if (Gesture.OnTap!=null)
				Gesture.OnTap();
			for (var i=0;i<Gesture.Taps.length;++i)
				Gesture.Taps[i]();
			if (event.type=="touchend")//触屏端一般会有延迟，因此需要在抬起的时候就触发，同时阻止默认触发。但是电脑端就不需要，如果要做的话会导致执行两次
			{
				Gesture.Element.onclick();//执行点击事件
				RemoveDefault();	
			}
			EndOneListen();//终止该次监听
		}
		function StartDbTap()//触发Tap事件或者click事件
		{
			Gesture.DbJudge=0;
			Gesture.TimeContinue=0;
			Gesture.GestureNow="DbTap";//将当前手势定义为DbTap
			if (Gesture.OnDbTap!=null)
				Gesture.OnDbTap();
			for (var i=0;i<Gesture.DbTaps.length;++i)
				Gesture.DbTaps[i]();
			if (event.type=="touchend")//触屏端一般会有延迟，因此需要在抬起的时候就触发，同时阻止默认触发。但是电脑端就不需要，如果要做的话会导致执行两次
			{
				Gesture.Element.ondblclick();//执行双击事件
				RemoveDefault();	
			};	
			EndOneListen();//终止该次监听
		}
	}
}
	